package commons.data;

import java.util.ArrayList;
import java.util.HashMap;
import commons.utils.Utils;
import commons.errors.ErrorsHandler;
import gnu.trove.list.array.TIntArrayList;


public class Model {

	public enum TypeField {INT, DBL, TXT, DAT};

	private ArrayList<String> vFieldName;
	private ArrayList<TypeField> vFieldType;
	private TIntArrayList vFieldSize;

	// une map pour retrouver l'index d'un nom de champ dans les vecteur ci-dessus
	private HashMap<String,Integer> map_Name_Index;


	public Model() {
		vFieldName = new ArrayList<String>();
		vFieldType = new ArrayList<TypeField>();
		vFieldSize = new TIntArrayList();
		map_Name_Index = new HashMap<String,Integer>();
	}

	// aide le GC
	public void clear() {
		if (vFieldName != null) { // peut etre a-t-on deja été cleared ...
			vFieldName.clear();
			vFieldType.clear();
			vFieldSize.clear();
			map_Name_Index.clear();
		}

		vFieldName = null;
		vFieldType = null;
		vFieldSize = null;
		map_Name_Index = null;
	}

	// Initialisation du model a partir du contenu d'un fichier d'entrée
	//  (sous forme d'un vecteur de String, une String par ligne)
	// Plusieurs version selon la version du format des données d'entrée
	public void initModel_v03(ArrayList<String> vLigne, int fstLine, int lastLine) {
		assert(fstLine<=lastLine); // c'est testé avant l'appel

		for (int i = fstLine ; i<=lastLine ; i++) {
			String ligne = vLigne.get(i);
			String[] detailField = Utils.mySplit(ligne, '§');
			
			if(detailField.length!=3) {
				ErrorsHandler.addError("Description incorrecte du modele (il n'y a pas 3 parties spérarées par des §) -> ligne n°" + (i+1));
				return;
			}

			if (detailField[0].trim().length()==0) {
				ErrorsHandler.addError("Le nom de l'attribut est incorrect (vide) -> ligne n°" + (i+1));
				return;
			}
			if (!detailField[1].equals("INT") && !detailField[1].equals("DBL") && !detailField[1].equals("TXT") && !detailField[1].equals("DAT")) {
				ErrorsHandler.addError("Le type d'attribut est incorect -> ligne n°" + (i+1) + " : " + detailField[1] + " (doit valoir INT, DBL, TXT ou DAT)");
				return;
			}
			if (!Utils.isInteger(detailField[2])) {
				ErrorsHandler.addError("La taille de l'attribut est incorrecte (pas un entier) -> ligne n°" + (i+1));
				return;
			}

			registerField(detailField[0], TypeField.valueOf(detailField[1]), Integer.parseInt(detailField[2]));
		}
	}



	// Utilisé lors de la construction du modèle, ou pour l'ajout de champ par l'algo
	public void registerField (String fieldName, TypeField fieldType, int fieldSize) {
		vFieldName.add(fieldName);
		vFieldType.add(fieldType);
		vFieldSize.add(fieldSize);
		map_Name_Index.put(fieldName, vFieldName.size()-1);
	}

	public boolean existField (String fieldName) {
		return map_Name_Index.containsKey(fieldName);
	}

	public int getIndexOf (String fieldName) {
		return map_Name_Index.get(fieldName);
	}

	public int getNumberOfField() {
		return vFieldName.size();
	}

	public String getFieldName (int indexOfField) {
		return vFieldName.get(indexOfField);
	}

	public TypeField getTypeOf(String fieldName) {
		return vFieldType.get(getIndexOf (fieldName));
	}
	public TypeField getTypeOf(int indexOfField) {
		return vFieldType.get(indexOfField);
	}
	public int getSizeOf(String fieldName) {
		return getSizeOf(getIndexOf (fieldName));
	}
	public int getSizeOf(int indexOfField) {
		return vFieldSize.get(indexOfField);
	}
	public ArrayList<String> getVFieldName() {
		return vFieldName;
	}

	// crée un sous-model ne contenant que les attributs de 'vAttrAConserver'
	public Model createModelFusionne (ArrayList<String> vAttrAConserver) {
		Model model_fusion = new Model();
		String fieldName;
		TypeField fieldType;
		int fieldSize;
		int index_field;

		for (int i = 0; i < vAttrAConserver.size(); i++) {
			fieldName = vAttrAConserver.get(i);
			index_field = map_Name_Index.get(fieldName);
			fieldType = vFieldType.get(index_field);
			fieldSize = vFieldSize.get(index_field);

			model_fusion.registerField(fieldName, fieldType, fieldSize);
		}
		return model_fusion;
	}

}
